#include "TcpServer.h"
#include "Logger.h"
#include "EventLoop.h"
#include <strings.h>

/**
 * @brief 检查loop
 *
 * @param loop
 * @return EventLoop*
 */
static EventLoop *CheckLoopNotNull(EventLoop *loop)
{
    if (loop == nullptr)
    {
        LOG_FATAL("%s:%s:%d TcpConnection Loop is null!", __FILE__, __FUNCTION__, __LINE__);
    }
    return loop;
}
/**
 * @brief Construct a new Tcp Server:: Tcp Server object
 *
 * @param loop
 * @param listenAddr
 * @param nameArg
 * @param option
 */
TcpServer::TcpServer(EventLoop *loop, const InetAddress &listenAddr, const std::string &nameArg, Option option)
    : loop_(CheckLoopNotNull(loop)), ipPort_(listenAddr.toIpPort()), name_(nameArg), acceptor_(new Acceptor(loop, listenAddr, option == kReusePort)), threadPool_(new EventLoopThreadPool(loop, nameArg)), connectionCallback_(), messageCallback_(), nextConnId_(1), started_(0)
{
    // 设置acceptor的新链接回调
    acceptor_->setNewConnectionCallBack(std::bind(&TcpServer::newConnecion, this, std::placeholders::_1, std::placeholders::_2));
}
TcpServer::~TcpServer()
{
    for (auto &it : connections_)
    {
        // 栈上shared_ptr
        TcpConnectionPtr conn(it.second);
        // 释放管理权
        it.second.reset();
        // 对应loop回调TcpConnecion销毁
        conn->getLoop()->runInLoop(std::bind(&TcpConnection::connectDestoryed, conn));
    }
}
// 设置线程池数量
void TcpServer::setThreadNum(int numThreads)
{
    threadPool_->setThreadNum(numThreads);
}
// 启动服务器
void TcpServer::start()
{
    if (started_++ == 0)
    {
        threadPool_->start(threadInitCallback_);                         // 启动线程池
        loop_->runInLoop(std::bind(&Acceptor::listen, acceptor_.get())); // mainloop上acceptor进行listen
    }
}

// 创建和移除链接
void TcpServer::newConnecion(int sockfd, const InetAddress &peerAddr)
{
    // 轮询获取subloop
    EventLoop *ioLoop = threadPool_->getNextLoop();
    // 名称
    char buff[64] = {0};
    sprintf(buff, "%s#%d", ipPort_.c_str(), nextConnId_);
    nextConnId_++;
    std::string connName = name_ + buff;

    LOG_INFO("TcpServer::newConnecion [%s] new connection [%s] from %s\n", name_.c_str(), connName.c_str(), peerAddr.toIpPort().c_str());
    // 获取本地ip&port
    sockaddr_in local;
    ::bzero(&local, sizeof(local));
    socklen_t addrlen = sizeof(local);
    if (::getsockname(sockfd, (sockaddr *)&local, &addrlen) < 0)
    {
        LOG_ERROR("sockets::getLocalAddr error");
    }
    InetAddress localAddr(local);
    // 创建链接
    TcpConnectionPtr conn(new TcpConnection(ioLoop, connName, sockfd, localAddr, peerAddr));
    connections_[connName] = conn;
    // 设置回调
    conn->setConnectionCallback(connectionCallback_);
    conn->setMessageCallback(messageCallback_);
    conn->setWriteCompleteCallback(writeCompleteCallback_);

    conn->setCloseCallback(std::bind(&TcpServer::removeConnecion, this, std::placeholders::_1));

    // subloop执行链接建立函数
    ioLoop->runInLoop(std::bind(&TcpConnection::connectEstablished, conn));
}
void TcpServer::removeConnecion(const TcpConnectionPtr &conn)
{
    loop_->runInLoop(std::bind(&TcpServer::removeConnecionInLoop, this, conn));
}
void TcpServer::removeConnecionInLoop(const TcpConnectionPtr &conn)
{
    LOG_INFO("TcpServer::removeConnecionInLoop [%s] connecion %s\n", name_.c_str(), conn->name().c_str());

    connections_.erase(conn->name());
    EventLoop *ioLoop = conn->getLoop();
    ioLoop->queueInLoop(std::bind(&TcpConnection::connectDestoryed, conn));
}